/***********************************
 * 本文件用于实现socket编程，一步到位实现
 * 分别提供了client和server的socket准备工作的一次性接口
 ************************************/

#pragma once
#include <cerrno>
#include <cstring>

#include <iostream>

#include <sys/types.h>
#include <sys/socket.h>

#include "Log.hpp"
#include "Sockaddr.hpp"

const static int defaultblock = 5;
const static int buffer_size = 1024;

// 基类(抽象类/接口类)
class Socket
{
public:
    // 创建套接字
    virtual bool SocketInit() = 0;
    // bind
    virtual bool Bind() = 0;
    // accept
    virtual bool Accept() = 0;
    // listen
    virtual bool Listen() = 0;
    // server端支持主动关闭，导致绑定失败的问题
    virtual bool ReBind() = 0;
    // read/recv
    virtual bool Recv(int fd) = 0;
    // write/send
    // virtual bool Send() = 0;
    // 拿到fd
    virtual int Getfd() = 0;
    // 拿listenfd
    virtual int GetListenfd() = 0;
    // 关闭fd
    virtual bool Closefd(int fd) = 0;
    // Server的Socket初始化
    bool ServerInit()
    {
        return SocketInit() && ReBind() && Bind() && Listen();
    }
};

// 派生类：用于实现TCP Server和Client 的套接字编程
class TCP_Server_Socket : public Socket
{
public:
    // 服务端套接字
    TCP_Server_Socket(uint16_t port)
        : _sockaddr(port)
    {
    }

    // Server
    virtual bool SocketInit()
    {
        _listenfd = socket(AF_INET, SOCK_STREAM, 0);
        if (_listenfd == -1)
        {
            _log.LogMessage(ClassFile, Error, "socket error, strerror : %s\n", strerror(errno));
            return false;
        }
        _log.LogMessage(ClassFile, Info, "socket success\n");
        return true;
    }
    // Server
    virtual bool Listen()
    {
        int ret = listen(_listenfd, defaultblock);
        if (ret == -1)
        {
            _log.LogMessage(ClassFile, Error, "listen error, strerror : %s\n", strerror(errno));
            return false;
        }
        _log.LogMessage(ClassFile, Info, "listen success\n");
        return true;
    }
    // Server
    virtual bool Bind()
    {
        int ret = bind(_listenfd, (sockaddr *)&_sockaddr.GetSockaddr(), _sockaddr.GetAddrlen());
        if (ret == -1)
        {
            _log.LogMessage(ClassFile, Error, "bind error, strerror : %s\n", strerror(errno));
            return false;
        }
        _log.LogMessage(ClassFile, Info, "bind success\n");
        return true;
    }
    // Server
    virtual bool ReBind()
    {
        int opt = 1;
        int ret = setsockopt(_listenfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
        if (ret == -1)
        {
            _log.LogMessage(ClassFile, Error, "setsockopt error, strerror : %s\n", strerror(errno));
            return false;
        }
        _log.LogMessage(ClassFile, Info, "setsockopt success\n");
        return true;
    }
    // Server
    virtual bool Accept()
    {
        sockaddr_in cilent_sockaddt_in;
        socklen_t cilent_sockaddt_in_addrlen;
        _sockfd = accept(_listenfd, (sockaddr *)&cilent_sockaddt_in, &cilent_sockaddt_in_addrlen);
        std::cout << _sockfd << std::endl;
        if (_sockfd == -1)
        {
            _log.LogMessage(ClassFile, Error, "accept error, strerror : %s\n", strerror(errno));
            return false;
        }
        _log.LogMessage(ClassFile, Info, "accept success\n");
        return true;
    }
    // Server
    virtual bool Recv(int fd)
    {
        char recv_buffer[buffer_size];
        int ret = recv(fd, recv_buffer, sizeof(recv_buffer) - 1, 0); // 默认阻塞IO
        // 读取成功
        if (ret > 0)
        {
            recv_buffer[ret] = 0;
            std::cout << "对端:" << recv_buffer << std::endl;
            return true;
        }
        // 读到末尾
        else if (ret == 0)
        {
            _log.LogMessage(ClassFile, Info, "对端关闭\n");
        }
        // 读取失败 / 非阻塞IO的没读到数据
        else
        {
            _log.LogMessage(ClassFile, Error, "读取失败\n");
        }
        return false;
    }

    virtual int Getfd() { return _sockfd; }
    virtual int GetListenfd() { return _listenfd; }

    virtual bool Closefd(int fd)
    {
        int ret = close(fd);
        if (ret == -1)
        {
            _log.LogMessage(ClassFile, Error, "close error, strerror : %s\n", strerror(errno));
            return false;
        }
        _log.LogMessage(ClassFile, Info, "close success\n");
        return true;
    }

private:
    int _sockfd;   // server 用于通信    的套接字
    int _listenfd; // server 用于listen 的套接字
    SockAddr _sockaddr;
};